
`define OP_ORA 'h00
`define OP_AND 'h01
`define OP_EOR 'h02
`define OP_ADC 'h03
// 5,6 分别是 sta,lda
`define OP_CMP 'h06
`define OP_SBC 'h07

module ALU (
    op1,
    op2,
    dest_out,
    P,
    opc,
    flg_out
);
`define OP_IS(hex) (opc==hex)
    input wire[7:0] op1,op2;
    input wire[7:0] P;
    output wire[7:0] dest_out;
    input wire[2:0]  opc;
    output wire[3:0] flg_out;

    wire[8:0] dest;

    wire[7:0]op2a = (`OP_IS(`OP_CMP)|`OP_IS(`OP_SBC)|`OP_IS(`OP_SBC)) ?~op2:op2;
    assign dest =
    `OP_IS(`OP_ADC)?({1'b0,op1}+{1'b0,op2a}+{8'd0,P[0]}):
    `OP_IS(`OP_SBC)?({1'b0,op1}+{1'b0,op2a}+{8'd0,P[0]}):       //如果使用减法,则会增加一些资源
    `OP_IS(`OP_ORA)?({1'b0,op1}|{1'b0,op2 }):
    `OP_IS(`OP_AND)?({1'b0,op1}&{1'b0,op2 }):
    `OP_IS(`OP_EOR)?({1'b0,op1}^{1'b0,op2 }):
    `OP_IS(`OP_CMP)?({1'b0,op1}+{1'b0,op2a}+9'd1):      //cmp
    0;
    wire fZ;
    wire fN;
    wire fC;
    wire fV;
    assign fZ = dest[7:0]==0;
    assign fN = dest[7];
    //assign fC = (`OP_IS(`OP_SBC)|`OP_IS(`OP_CMP))?~dest[8]:dest[8];     //SBC可以取反变成ADC,但C位需要取反
    assign fC = ~(`OP_IS(`OP_ADC)|`OP_IS(`OP_SBC)|`OP_IS(`OP_CMP))?P[0]:        //除了ADC,SBC,CMP,其他的都不变
        (dest[8] /* ^(`OP_IS(`OP_SBC)|`OP_IS(`OP_CMP))*/);
    assign fV =
        ~(`OP_IS(`OP_ADC)|`OP_IS(`OP_SBC))?P[6]:        //除了ADC与SBC,其他都不变
        (((op1[7]&op2a[7])&~dest[7])          //情况1,如果op1与op2皆为负数,结果为正数.则溢出
        |((~op1[7]&~op2a[7])&dest[7]))        //情况2,如果op1与op2皆为正数,结果为负数,则溢出
    ;
    assign flg_out = {fN,fV,fZ,fC};
    assign dest_out = dest[7:0];
endmodule



module c6502(
    addr,
    dat,
    clk_in,
    rst_n,
    irq,
    nmi,
    rw,

    is_pc,
    is_sp,
    is_db,
);
    input wire clk_in;
    inout wire[7:0] dat;
    input wire rst_n;
    output reg[15:0] addr;
    output wire rw;     reg rw_reg = 'b1; assign rw = rw_reg;
    input wire irq;
    input wire nmi;

    reg [7:0] insn_reg;

    reg [15:0] pc = 'd0;      //程序计数器
    reg [15:0] dbus = 'd0;    //数据总线

    reg [7:0] A;
    reg [7:0] X;
    reg [7:0] Y;
    reg [7:0] P;
    reg [7:0] S;


    input wire is_pc;
    input wire is_sp;
    input wire is_db;

    reg addr_inc_reg = 'd0;
    always @(posedge clk_in) begin
        addr_inc_reg <= 1'b1;
    end

    wire[15:0] addr_inc = addr + 'b1;

    /*
        只有地址线存在累加器.
           ___>___+1_(neg)_________
          /              \   \     \
         /                \    \    \
        addr <--(pos)----| pc | S | dbus |




        算数逻辑
                +-------------------
                |                   >result
            op1 >     ALU           >co
            op2 >                   >zo
            ci  >                   >no
            opc >                   >vo
                +-------------------|


        op1 指向三个操作寄存器
             /  A
        op1 <   X    (只包括inx,dex,cmp)
             \  Y    (只包括iny,dey,cmp)

             /  M
        op2 <  'h00  (只包括inx,dex)
             \ 'hff  (只包括iny,dey)

            / P[0]      (除了cmp,inx,iny,dex,dey)
        ci -- 1'b0      (cmp...)

             / ireg[7:5]
        opc <  add (inc,dec,...)
             \ cmp (cpx,cpy)


              / 'bz     (inx,iny,dex,dey..)指令
        co  >>  P[0]    cmo,adc,sbc ...

        zo  >> P[1]     全部指令
        no  >> P[7]     全部指令
        vo  >> P[6]

    */



    always @(*) begin
        if(clk_in)begin
            if(is_sp)addr <= {8'h01,S};
            else if(is_db)addr <= dbus;
            else if(clk_in) addr <= pc;
            else;
        end
        else begin
            if(~nmi)       pc<='hfffa;
            else if(~rst_n)pc<='hfffc;
            else if(~irq)  pc<='hfffe;
            else if(is_pc)begin pc<=addr_inc; end
            else if(is_sp) S <=addr_inc;
            else if(is_db) S <=addr_inc;
            else begin end
        end
    end

    assign op1 = isX?X:isY?Y:A;
    assign op2 = dat;


    reg[5:0] status;

    wire is_alu = status[0];

    wire[7:0] op1;
    wire[7:0] op2;
    wire[7:0] dest_out;
    wire[2:0] opc;
    wire[3:0] flg_out;

    ALU alu(
        op1,
        op2,
        dest_out,
        P,
        opc,
        flg_out
    );

    reg isX = 1'd0;
    reg isY = 1'd0;

    always @(negedge clk_in) begin

    end



endmodule